package zl.applet.puzzle;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.KeyStroke;
import javax.swing.Timer;

//窗体继承自JFrame
public class PuzzleGame extends JFrame
{
	private static final long serialVersionUID = 1L;
	private Timer time;      //声明计时器
	private String result;   //用来保存成功标记
	private final String fileName = "source" + File.separatorChar + "0.jpg";
	private String newName;
	private BufferedImage bi;     //声明图片缓冲器获取图片资源
	private JPanel jpLeft;   //声明面板
	private JPanel jpRight;
	private JLabel jlSecond;   //声明标签
	private JLabel jlPace;   
	private JLabel jlImage;
	private JButton jbStart;   //声明按钮
	private JRadioButton jrb1; //声明单选按钮
	private JRadioButton jrb2;
	private JRadioButton jrb3;
	private int second;   //存储所用时间（秒）
	private int pace;    //存储所用步
	private int row;     //游戏的行
	private int col;     //游戏的列
	private MyButton emptyButton;   //空白按钮

	private int pictureW = 300;    //游戏图片的宽
	private int pictureH = 390;    //游戏图片的高

	public PuzzleGame()  //无参构造
	{
		this.initial();
	}

	//初始化窗体
	public void initial()
	{
		this.setTitle("拼图游戏");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //设置窗体的默认关闭操作
		this.setResizable(false);   //设置窗体不可改变大小
		this.setSize(this.pictureW,this.pictureH + 30);      //设置窗体的大小
		this.setLocation(           //定位窗体
			this.getToolkit().getScreenSize().width / 2 - this.getWidth() / 2,
			this.getToolkit().getScreenSize().height / 2 - this.getHeight() / 2
		);
		this.addWindowListener(new WindowAdapter(){    //响应窗体关闭事件
			public void windowClosing(WindowEvent e)
			{
				//匿名内部类
				int w = getWidth();
				for(int i = w; i > 0; i-=10)
				{
					setSize(i,5);  //改变窗体大小
					setLocation(   //重新定位窗体
						getToolkit().getScreenSize().width / 2 - getWidth() / 2,
						getToolkit().getScreenSize().height / 2 - getHeight() / 2	
					);
				}
			}
		});
		
		this.result = "";
		this.pace = 0;
		this.second = 0;
		this.jlSecond = new JLabel(Integer.toString(this.second));  //实例化用来显示时间的标签
		this.jlPace = new JLabel(Integer.toString(this.pace));
		this.jrb1 = new JRadioButton("易");  //实例化单选按钮
		this.jrb1.setSelected(true);   //默认为选中状态
		this.jrb2 = new JRadioButton("中");
		this.jrb3 = new JRadioButton("难");
		
		this.time = new Timer(1000,new ActionListener(){   //实例化计时器、
			public void actionPerformed(ActionEvent e)
			{
				if(!jbStart.isEnabled())
				{ 
					//如果单击“开始按钮”、则开始计数
					second++;
					jlSecond.setText(Integer.toString(second));
				}
				time.restart();  //重新启动
			}
		});
		
		this.jbStart = this.getjbStart();
		if(this.newName == null)   //如果自定义图片失败
			this.bi = this.getImageSource();  //则调用方法重新加载资源图片
		this.jlImage = new JLabel(this.zoomImage(this.bi));  //实例化图片标签
		this.jlImage.setSize(150,195);  //设置图片标签的大小		
		this.createJPRight();   //创建右边面板
		this.getContentPane().add(this.jpRight);  //将右边面板添加到窗口容器
		this.setJMenuBar(this.jmbMain());    //将菜单栏设置为窗体的菜单
	} 

	private JButton getjbStart()
	{
		this.jbStart = new JButton("开始");  //实例化按钮
		this.jbStart.addActionListener(new ActionListener(){   //添加事件监听器
			public void actionPerformed(ActionEvent e)
			{
				if(jrb1.isSelected())  //易
				{
					row = 3;
					col = 3;
				}
				else if(jrb2.isSelected())  //中
				{
					row = 5;
					col = 5;
				}
				else   //难
				{
					row = 6;
					col = 6;
				}
				createJPLeft();  //调用方法创建左边面板
				pace = 0;   //清空"步"
				second = 0;  //清空"秒"
				jbStart.setEnabled(false);  //“开始”按钮不可用
				time.start();   //开启计时器
			}
		});
		return this.jbStart;   //返回按钮
	}

	//创建菜单栏
	private JMenuBar jmbMain()
	{	
		JMenuBar jmb = new JMenuBar();    //声明菜单栏

		//给菜单栏添加菜单
		jmb.add(this.jmOpen());    
		jmb.add(this.jmHelp());

		//返回菜单栏
		return jmb;   
	}
	
	//创建“开始”菜单
	private JMenu jmOpen()
	{
		JMenu jm = new JMenu("开始(O)");   //创建菜单
		jm.setMnemonic('O');    //给菜单添加快捷键

		//给菜单添加菜单项
		jm.add(this.jmiSelect());
		jm.add(this.jmiNew());
		jm.add(this.jmiQuit());

		//返回菜单
		return jm;
	}

	//创建“帮助”菜单
	private JMenu jmHelp()
	{
		JMenu jm = new JMenu("帮助(H)");   //创建菜单

		//给菜单添加菜单项
		jm.setMnemonic('H');
		jm.add(this.jmiOperation());
		jm.add(this.jmiAbout());

		//返回菜单
		return jm;
	}

	//创建“选择图片”菜单项
	private JMenuItem jmiSelect()
	{
		JMenuItem jmi = new JMenuItem("选择图片");   //创建菜单栏
		jmi.setAccelerator(KeyStroke.getKeyStroke("ctrl S"));   //设置快速访问键
		jmi.addActionListener(new ActionListener(){      //注册事件
			public void actionPerformed(ActionEvent e)
			{
				//创建文件夹选择器、默认目录为当前的图片资源所在目录
				JFileChooser jfc = new JFileChooser(fileName);   
				if(jfc.showOpenDialog(PuzzleGame.this) == JFileChooser.OPEN_DIALOG)
				{
					//如果有选择文件
					newName = jfc.getSelectedFile().getPath();    //获取选择的文件的路径
					bi = getImageSource();  //根据所选文件获取图片资源
					if (bi == null)
						newName = null;  //如果图片为空、则清空所选文件名
					newGame();   //“新游戏”方法 初始化重新加载窗口
				}
			}
		});

		//返回菜单项
		return jmi;
	}

	//创建“新游戏”菜单项
	private JMenuItem jmiNew()
	{
		JMenuItem jmi = new JMenuItem("新游戏");    //声明菜单项
		jmi.setAccelerator(KeyStroke.getKeyStroke("ctrl N"));   //设置快速访问键
		jmi.addActionListener(new ActionListener(){    //注册事件
			//匿名内部类
			public void actionPerformed(ActionEvent e)
			{
				newGame();   //调用外部类的“新游戏”方法、重新加载窗体
			}
		});

		//返回菜单项
		return jmi;
	}

	//创建“退出”菜单项
	private JMenuItem jmiQuit()
	{
		JMenuItem jmi = new JMenuItem("退出");   //声明菜单项
		jmi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0));   //设置快速访问键
		jmi.addActionListener(new ActionListener(){    //注册事件
			public void actionPerformed(ActionEvent e)
			{
				System.exit(0);   //退出JAVA程序
			}
		});

		//返回菜单项
		return jmi;
	}

	//创建“说明”菜单项
	private JMenuItem jmiOperation()
	{
		JMenuItem jmi = new JMenuItem("操作说明");   //声明菜单项
		jmi.setAccelerator(KeyStroke.getKeyStroke("F1"));  //给菜单项添加快速访问键
		jmi.addActionListener(new ActionListener(){     //给菜单项添加事件监听器
			public void actionPerformed(ActionEvent e)
			{
				//响应事件
				JOptionPane.showMessageDialog(null,
					"操作提示：鼠标单击移动图片、当图片如左图所示即成功！！！",
					"消息",JOptionPane.INFORMATION_MESSAGE);
			}
		});

		//返回菜单项
		return jmi;
	}

	//创建“关于”菜单项
	private JMenuItem jmiAbout()
	{
		JMenuItem jmi = new JMenuItem("关于");     //声明菜单项
		jmi.setAccelerator(KeyStroke.getKeyStroke("ctrl A"));    //给菜单项添加快速访问键
		jmi.addActionListener(new ActionListener(){         //给菜单项添加事件监听器
			public void actionPerformed(ActionEvent e)
			{
				JOptionPane.showMessageDialog(null,
					"版本：1.0\n作者：张乐\nEmail：1603013767@qq.com",
					"消息",JOptionPane.INFORMATION_MESSAGE);
			}
		});

		//返回菜单项
		return jmi;
	}

	//新游戏、重新布局窗体
	private void newGame()
	{
		this.getContentPane().removeAll();  //清空面板容器
		this.initial();   //初始化窗体
		this.setVisible(true);   //重新显示窗体
	}

	//获得图片
	private BufferedImage getImageSource()
	{
		//this.jbStart.setEnabled(false);  //要更改图片。则将”开始“按钮不可用
		BufferedImage bi = null;   //声明图片缓冲器对象
		try
		{
			if(this.newName != null)   //如果所选文件名不为空
				bi = ImageIO.read(new File(this.newName));  //读取图片到图片缓冲器对象
			else  //否则调用默认文件名
				bi = ImageIO.read(new File(this.fileName));  //读取图片到图片缓冲器对象
			if(bi == null)
				throw new IOException();
			if(!(bi.getWidth() == this.pictureW && bi.getHeight() == this.pictureH))  //判断图片大小是否符合要求
			{
				JOptionPane.showMessageDialog(this,"图片尺寸应为(像素)  X：" + 
					this.pictureW + "  Y：" + this.pictureH,"消息",JOptionPane.INFORMATION_MESSAGE);
				return null;
			}
		}
		catch(IOException e)
		{
			e.printStackTrace();
			JOptionPane.showMessageDialog(this,"图片加载错误、！！！","消息",JOptionPane.INFORMATION_MESSAGE);
			return null;
		}
		//this.jbStart.setEnabled(true);  //如果图片更改成功、则”开始“按钮为可用
		return bi;
	}

	//缩放图片
	private ImageIcon zoomImage(BufferedImage bi)
	{
		if(bi == null)
			return null;
		//声明指定大小的图片缓冲器
		BufferedImage image = new BufferedImage(150,195,BufferedImage.TYPE_INT_ARGB);
		AffineTransform at = new AffineTransform();
		at.setToScale(0.5,0.5);
		AffineTransformOp ato = new AffineTransformOp(at,null);
		ato.filter(bi,image);
		return new ImageIcon(image);   //返回缩放后的图片
	}

	//创建右边面板
	private void createJPRight()
	{
		this.jpRight = new JPanel();    //实例化右边面板
		//this.jpRight.setSize(150,450);    //设置面板大小
		//设置面板的布局管理器
		this.jpRight.setLayout(new BoxLayout(this.jpRight,BoxLayout.PAGE_AXIS));

		JPanel temp = new JPanel();  //中间面板

		JLabel jlText = new JLabel("原始图片");  //声明标签
		temp.add(jlText);    //将标签添加到中间面板
		this.jpRight.add(temp);   //将中间面板添加到右边面板
		
		temp = new JPanel();
		temp.add(this.jlImage);   //将图片标签添加到中间面板
		this.jpRight.add(temp);  

		temp = new JPanel();
		temp.add(new JLabel("秒："));  //添加标签
		temp.add(this.jlSecond);  //将显示时间的标签添加到中间面板
		this.jpRight.add(temp); //将中间面板添加到右边面板

		temp = new JPanel();
		temp.add(new JLabel("步："));  //添加标签
		temp.add(this.jlPace);     //将显示”步“的标签添加到中间面板
		this.jpRight.add(temp);   //将中间面板添加到右边面板

		temp = new JPanel();
		ButtonGroup bg = new ButtonGroup();  //实例化按钮组
		bg.add(this.jrb1);  //将单选单选按钮添加到按钮组		
		bg.add(this.jrb2);		
		bg.add(this.jrb3);
		
		temp.add(this.jrb1);  //将单选按钮添加到中间面板
		temp.add(this.jrb2);
		temp.add(this.jrb3);
		this.jpRight.add(temp);
		
		temp = new JPanel();
		temp.add(this.jbStart);  //将”开始“按钮添加到中间面板	
		this.jpRight.add(temp);

		temp = new JPanel();
		temp.add(new JLabel("(ctrl + N 强制新游戏)"));   //添加标签
		this.jpRight.add(temp);
	}

	//创建左边面板
	private void createJPLeft()
	{
		this.jpLeft = new JPanel();    //实例化左边面板
		//this.jpLeft.setSize(310,400);
		this.setSize(620,440);
		//设置面板的布局管理器
		this.jpLeft.setLayout(new GridLayout(this.row,this.col));
		this.getContentPane().add(this.jpLeft,0);     //将左边面板添加到窗口容器
		this.getContentPane().setLayout(new GridLayout(1,2));
		this.setLocation(           //定位窗体
			this.getToolkit().getScreenSize().width / 2 - this.getWidth() / 2,
			this.getToolkit().getScreenSize().height / 2 - this.getHeight() / 2
		);
		MyButton[][] mbs = this.getButtons();  //获取相应等级所需要的按钮组
		//循环将按钮添加到左边面板
		for(int i = 0; i < this.row; i++)
		{
			for(int j = 0; j < this.col; j++)
			{
				this.jpLeft.add(mbs[i][j]);
			}
		}
	}

	//根据等级生成按钮组
	private MyButton[][] getButtons()
	{
		//此按钮（MyButton）为自定义按钮、扩展属性、row col用来标示按钮所在的行和列
		MyButton[][] mbs = new MyButton[this.row][this.col];  //根据等级声明二维数组
		this.emptyButton = new MyButton(0,this.col - 1);   //本游戏、设置右上角第一个按钮为空白按钮
		ArrayList<ImageIcon> images = this.divisionImage();  //调用方法获得、拆分并随即排序后的图片集合
		//根据等级要求的行、列、求得单个按钮的宽、高
		int w = this.pictureW / this.col;
		int h = this.pictureH / this.row;
		//循环生成按钮、并添加到二维数组
		for(int i = 0; i < this.row; i++)  //循环行
		{
			for(int j = 0; j < this.col; j++)   //循环列
			{
				MyButton mb = null;   //声明按钮
				if(i == 0 && j == this.col - 1)   
					mb = emptyButton;  //设置右上角的位置为空白按钮
				else
					mb = new MyButton(i,j);  //根据位置实例化自定义的按钮
				mb.setSize(w,h);   //设置按钮大小
				mb.setIcon(images.get(i * this.col + j));   //设置按钮的背景图、从图片集合取出
				mb.addActionListener(new ActionListener(){     //给按钮添加事件监听器
					public void actionPerformed(ActionEvent e)
					{
						MyButton mb = (MyButton)(e.getSource());  //获取事件源
						buttonOper(mb);
					}
				});
				mbs[i][j] = mb;  //将按钮添加到二维数组
			}
		}
		return mbs;
	}

	//响应单击按钮操作
	private void buttonOper(MyButton mb)
	{
		if(Math.abs((mb.getRow()-emptyButton.getRow())) + Math.abs((mb.getCol()-emptyButton.getCol())) == 1)
		{
			//判断按钮是否为空白按钮的相邻按钮
			//完成转换按钮功能
			emptyButton.setIcon(mb.getIcon());  //将此按钮的背景图设置为空白按钮的背景图
			mb.setIcon(null);    //将此按钮的背景图设为空
			emptyButton = mb;    //将此按钮设为空白按钮
			jlPace.setText(Integer.toString(++pace));  //转换成功、记做一步
			String temp = "";  //声明空白字符串
			//循环当前左边面板所有子按钮
			for(int i = 0; i < jpLeft.getComponents().length; i++)
			{
				//获取按钮上的图片
				ImageIcon ii = ((ImageIcon)(((MyButton)(jpLeft.getComponents()[i])).getIcon()));
				if(ii != null)
					temp += ii.getDescription();  //如果图片不为空、则获取图片的描述文本
				else
					temp += "empty";   //如果图片为空、则加上指定文本
			}
			if(temp.equals(result))   //判断文本是否和结果相等
			{
				//完成游戏
				JOptionPane.showMessageDialog(
					PuzzleGame.this,"恭喜、成功！！！\n" + 
					second + "秒  " + pace + "步","消息",JOptionPane.INFORMATION_MESSAGE);
				this.newGame();   //重新加载窗口
			}
		}
	}

	//分割图片
	private ArrayList<ImageIcon> divisionImage()
	{
		//this.bi  为本游戏的图片资源
		//根据等级要求的行、列、求得单个按钮的宽、高
		int w = this.pictureW / this.col;
		int h = this.pictureH / this.row;
		ArrayList<ImageIcon> images = new ArrayList<ImageIcon>();   //声明图片集合
		//循环切割图片
		for(int i = 0; i < this.row; i++)
		{
			for(int j = 0; j < this.col; j++)
			{
				if(i == 0 && j == this.col - 1)   //如果为右上角则中断当前循环进入一下轮循环、
					continue;
				else
					//根据条件切割出图片
					images.add(new ImageIcon(this.bi.getSubimage(j * w,i * h,w,h),
						Integer.toString(i * this.col + j)));  //将图片加入到集合、给图片添加描述
			}
		}
		//循环集合
		for(int i = 0; i < images.size(); i++)
		{
			//this.result  用来保存完整图片的描述字符串   用来验证是否完成游戏
			//循环获取图片的描述、
			if(i == this.col - 1)
				this.result += "empty";   //右上角的位置加上指定字符串
			this.result += images.get(i).getDescription();
		}
		Collections.shuffle(images);   //打乱图片集合
		//右上角位置放置空白按钮
		images.add(this.col - 1,new ImageIcon(new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB),"empty"));
		//返回图片集合
		return images;
	}
}